package com.study.lxy.security.sm2;

import com.study.lxy.security.SM2Key;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.io.IOException;
import java.math.BigInteger;

public class SM2Utils {

    //生成随机秘钥对
    public static String prik = "";
    // 国密规范正式公钥
    public static String pubk = "";

    public static void generateKeyPair(){
        SM2 sm2 = SM2.newInstance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();
        prik= ByteUtils.toHexString(privateKey.toByteArray());
        pubk=ByteUtils.toHexString(publicKey.getEncoded());
        System.out.println("公钥: " + pubk);
        System.out.println("私钥: " + prik);
    }

    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException {
        if (publicKey == null || publicKey.length == 0) {
            return null;
        }

        if (data == null || data.length == 0) {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.newInstance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.init_enc(sm2, userKey);
        cipher.encrypt(source);
        byte[] c3 = new byte[32];
        cipher.doFinal(c3);

        //C1 C2 C3拼装成加密字串
        return ByteUtils.toHexString(c1.getEncoded()) + ByteUtils.toHexString(source) + ByteUtils.toHexString(c3);
    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException {
        if (privateKey == null || privateKey.length == 0) {
            return null;
        }

        if (encryptedData == null || encryptedData.length == 0) {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = ByteUtils.toHexString(encryptedData);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = ByteUtils.fromHexString(data.substring(0,130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = ByteUtils.fromHexString(data.substring(130,130 + 2 * c2Len));
        byte[] c3 = ByteUtils.fromHexString(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));

        SM2 sm2 = SM2.newInstance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.init_dec(userD, c1);
        cipher.decrypt(c2);
        cipher.doFinal(c3);

        //返回解密结果
        return c2;
    }

    public static void main(String[] args) throws Exception {
        generateKeyPair();
        pubk = "04919f930419cd55b30f7481cd40b3769e27587cbe7c95562bd5278762ac720f1c6bc353de0c475800b9faa6c906531c010daa780e5ddde5a32359175db49a5959";
        prik = "6261c932658c0a31e6eb72b47315b96ec297ef2d22da23fc251fee108acbaef9";
        String plainText = "测试一下";
        byte[] sourceData = plainText.getBytes();
        System.out.println("加密姓名: ");
        String cipherText = SM2Utils.encrypt(ByteUtils.fromHexString(pubk), sourceData);
        System.out.println(cipherText);
        System.out.println("解密姓名: ");
        plainText = new String(SM2Utils.decrypt(ByteUtils.fromHexString(prik), ByteUtils.fromHexString(cipherText)));
        System.out.println(plainText);
    }
}
